Move "move-focus" signals from several widgets to GtkWidget to enable more
authorMichael Natterer <mitch@imendio.com>
Mon, 4 Jun 2007 15:00:22 +0000 (15:00 +0000)
committerMichael Natterer <mitch@src.gnome.org>
Mon, 4 Jun 2007 15:00:22 +0000 (15:00 +0000)
2007-06-04  Michael Natterer  <mitch@imendio.com>

Move "move-focus" signals from several widgets to GtkWidget to
enable more flexible costomization of keyboard navigation via
bindings. Fixes bug #414947.

* gtk/gtkwidget.c: add "move-focus" binding signal, default to
calling the toplevel GtkWindow's "move-focus" vfunc.

* gtk/gtktextview.[ch]
* gtk/gtkwindow.[ch]: remove "move-focus" signals and add compat
code that makes sure that both emitting the signal on the widget
and overriding the virtual functions keeps working as before.

* gtk/gtktoolbar.c: remove "move-focus" signal here too and use
GtkWidget's signal. This change slightly changes keyboard
navigation in toolbars. I'll fix the behavior if somebody can
explain me if and how exactly the new behavior is broken.

svn path=/trunk/; revision=18025

ChangeLog
gtk/gtktextview.c
gtk/gtktextview.h
gtk/gtktoolbar.c
gtk/gtkwidget.c
gtk/gtkwindow.c
gtk/gtkwindow.h

index 66dde2dc025a1bb7137b515edd513935796c312b..3285c4ec493ecbe886a87ba75e79d7663c9dbfdb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2007-06-04  Michael Natterer  <mitch@imendio.com>
+
+       Move "move-focus" signals from several widgets to GtkWidget to
+       enable more flexible costomization of keyboard navigation via
+       bindings. Fixes bug #414947.
+
+       * gtk/gtkwidget.c: add "move-focus" binding signal, default to
+       calling the toplevel GtkWindow's "move-focus" vfunc.
+
+       * gtk/gtktextview.[ch]
+       * gtk/gtkwindow.[ch]: remove "move-focus" signals and add compat
+       code that makes sure that both emitting the signal on the widget
+       and overriding the virtual functions keeps working as before.
+
+       * gtk/gtktoolbar.c: remove "move-focus" signal here too and use
+       GtkWidget's signal. This change slightly changes keyboard
+       navigation in toolbars. I'll fix the behavior if somebody can
+       explain me if and how exactly the new behavior is broken.
+
 2007-06-04  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkmarshalers.list:
index 6c7f6848218fcea1f90272d3a612c29212775895..f37a04de8108d2d6bc0f7b0d2c55c9c1e28d049a 100644 (file)
@@ -133,7 +133,6 @@ enum
   COPY_CLIPBOARD,
   PASTE_CLIPBOARD,
   TOGGLE_OVERWRITE,
-  MOVE_FOCUS,
   MOVE_VIEWPORT,
   SELECT_ALL,
   TOGGLE_CURSOR_VISIBLE,
@@ -206,6 +205,8 @@ static gint gtk_text_view_expose_event         (GtkWidget        *widget,
 static void gtk_text_view_draw_focus           (GtkWidget        *widget);
 static gboolean gtk_text_view_focus            (GtkWidget        *widget,
                                                 GtkDirectionType  direction);
+static void gtk_text_view_move_focus           (GtkWidget        *widget,
+                                                GtkDirectionType  direction_type);
 static void gtk_text_view_select_all           (GtkWidget        *widget,
                                                 gboolean          select);
 
@@ -278,7 +279,7 @@ static void gtk_text_view_copy_clipboard   (GtkTextView           *text_view);
 static void gtk_text_view_paste_clipboard  (GtkTextView           *text_view);
 static void gtk_text_view_toggle_overwrite (GtkTextView           *text_view);
 static void gtk_text_view_toggle_cursor_visible (GtkTextView      *text_view);
-static void gtk_text_view_move_focus       (GtkTextView           *text_view,
+static void gtk_text_view_compat_move_focus(GtkTextView           *text_view,
                                             GtkDirectionType       direction_type);
 static void gtk_text_view_unselect         (GtkTextView           *text_view);
 
@@ -490,7 +491,16 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   widget_class->motion_notify_event = gtk_text_view_motion_event;
   widget_class->expose_event = gtk_text_view_expose_event;
   widget_class->focus = gtk_text_view_focus;
-  
+
+  /* need to override the base class function via override_class_closure,
+   * because the signal slot is not available in GtkWidgetCLass
+   */
+  g_signal_override_class_closure (g_signal_lookup ("move-focus",
+                                                    GTK_TYPE_WIDGET),
+                                   GTK_TYPE_TEXT_VIEW,
+                                   g_cclosure_new (G_CALLBACK (gtk_text_view_move_focus),
+                                                   NULL, NULL));
+
   widget_class->drag_begin = gtk_text_view_drag_begin;
   widget_class->drag_end = gtk_text_view_drag_end;
   widget_class->drag_data_get = gtk_text_view_drag_data_get;
@@ -517,7 +527,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   klass->copy_clipboard = gtk_text_view_copy_clipboard;
   klass->paste_clipboard = gtk_text_view_paste_clipboard;
   klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
-  klass->move_focus = gtk_text_view_move_focus;
+  klass->move_focus = gtk_text_view_compat_move_focus;
   klass->set_scroll_adjustments = gtk_text_view_set_scroll_adjustments;
 
   /*
@@ -787,16 +797,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                  _gtk_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
-  signals[MOVE_FOCUS] =
-    g_signal_new (I_("move_focus"),
-                 G_OBJECT_CLASS_TYPE (gobject_class),
-                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                 G_STRUCT_OFFSET (GtkTextViewClass, move_focus),
-                 NULL, NULL,
-                 _gtk_marshal_VOID__ENUM,
-                 G_TYPE_NONE, 1,
-                 GTK_TYPE_DIRECTION_TYPE);
-  
   signals[SET_SCROLL_ADJUSTMENTS] =
     g_signal_new (I_("set_scroll_adjustments"),
                  G_OBJECT_CLASS_TYPE (gobject_class),
@@ -3927,9 +3927,9 @@ gtk_text_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
          obscure = TRUE;
        }
       else
-       gtk_text_view_move_focus (text_view,
-                                 (event->state & GDK_SHIFT_MASK) ?
-                                 GTK_DIR_TAB_BACKWARD: GTK_DIR_TAB_FORWARD);
+       g_signal_emit_by_name (text_view, "move-focus",
+                               (event->state & GDK_SHIFT_MASK) ?
+                               GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
 
       retval = TRUE;
     }
@@ -4384,6 +4384,17 @@ gtk_text_view_focus (GtkWidget        *widget,
     }
 }
 
+static void
+gtk_text_view_move_focus (GtkWidget        *widget,
+                          GtkDirectionType  direction_type)
+{
+  GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+
+  if (GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus)
+    GTK_TEXT_VIEW_GET_CLASS (text_view)->move_focus (text_view,
+                                                     direction_type);
+}
+
 /*
  * Container
  */
@@ -4894,7 +4905,7 @@ gtk_text_view_move_cursor_internal (GtkTextView     *text_view,
       if (!gtk_widget_keynav_failed (GTK_WIDGET (text_view),
                                      leave_direction))
         {
-          gtk_text_view_move_focus (text_view, leave_direction);
+          g_signal_emit_by_name (text_view, "move-focus", leave_direction);
         }
     }
   else
@@ -5508,16 +5519,43 @@ gtk_text_view_get_accepts_tab (GtkTextView *text_view)
 }
 
 static void
-gtk_text_view_move_focus (GtkTextView     *text_view,
-                          GtkDirectionType direction_type)
+gtk_text_view_compat_move_focus (GtkTextView     *text_view,
+                                 GtkDirectionType direction_type)
 {
-  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (text_view));
+  GSignalInvocationHint *hint = g_signal_get_invocation_hint (text_view);
 
-  if (!GTK_WIDGET_TOPLEVEL (toplevel))
-    return;
+  /*  as of GTK+ 2.12, the "move-focus" signal has been moved to GtkWidget,
+   *  the evil code below makes sure that both emitting the signal and
+   *  calling the virtual function directly continue to work as expetcted
+   */
+
+  if (hint->signal_id == g_signal_lookup ("move-focus", GTK_TYPE_WIDGET))
+    {
+      /*  if this is a signal emission, chain up  */
+
+      GValue instance_and_params[2] = { { 0, }, { 0, } };
+      GValue return_value = { 0, };
+
+      g_value_init (&instance_and_params[0], GTK_TYPE_WIDGET);
+      g_value_set_object (&instance_and_params[0], text_view);
+
+      g_value_init (&instance_and_params[1], GTK_TYPE_DIRECTION_TYPE);
+      g_value_set_enum (&instance_and_params[1], direction_type);
 
-  /* Propagate to toplevel */
-  g_signal_emit_by_name (toplevel, "move_focus", direction_type);
+      g_signal_chain_from_overridden (instance_and_params, &return_value);
+
+      g_value_unset (&instance_and_params[0]);
+      g_value_unset (&instance_and_params[1]);
+      g_value_unset (&return_value);
+    }
+  else
+    {
+      /*  otherwise emit the signal, since somebody called the virtual
+       *  function directly
+       */
+
+      g_signal_emit_by_name (text_view, "move-focus", direction_type);
+    }
 }
 
 /*
index 90629353308052f05ec59d9e18a135895ae23078..d5223118e5247ea19902962c2d36f10078364a05 100644 (file)
@@ -195,11 +195,13 @@ struct _GtkTextViewClass
   /* overwrite */
   void (* toggle_overwrite) (GtkTextView *text_view);
 
-  /* propagates to GtkWindow move_focus */
+  /* as of GTK+ 2.12 the "move-focus" signal has been moved to GtkWidget,
+   * so this is merley a virtual function now. Overriding it in subclasses
+   * continues to work though.
+   */
   void (* move_focus)       (GtkTextView     *text_view,
-                             GtkDirectionType direction);  
-  
-  
+                             GtkDirectionType direction);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
index 7f19352e69e88573c75f2bdeeb75722fe3d41953..8230c1149f86fe29ccc3d37f5a3b93a9168738ea 100644 (file)
@@ -103,7 +103,6 @@ enum {
   ORIENTATION_CHANGED,
   STYLE_CHANGED,
   POPUP_CONTEXT_MENU,
-  MOVE_FOCUS,
   FOCUS_HOME_OR_END,
   LAST_SIGNAL
 };
@@ -173,6 +172,8 @@ static void       gtk_toolbar_style_set            (GtkWidget           *widget,
                                                    GtkStyle            *prev_style);
 static gboolean   gtk_toolbar_focus                (GtkWidget           *widget,
                                                    GtkDirectionType     dir);
+static void       gtk_toolbar_move_focus           (GtkWidget           *widget,
+                                                   GtkDirectionType     dir);
 static void       gtk_toolbar_screen_changed       (GtkWidget           *widget,
                                                    GdkScreen           *previous_screen);
 static void       gtk_toolbar_map                  (GtkWidget           *widget);
@@ -203,8 +204,6 @@ static void       gtk_toolbar_orientation_changed  (GtkToolbar          *toolbar
                                                    GtkOrientation       orientation);
 static void       gtk_toolbar_real_style_changed   (GtkToolbar          *toolbar,
                                                    GtkToolbarStyle      style);
-static gboolean   gtk_toolbar_move_focus           (GtkToolbar          *toolbar,
-                                                   GtkDirectionType     dir);
 static gboolean   gtk_toolbar_focus_home_or_end    (GtkToolbar          *toolbar,
                                                    gboolean             focus_home);
 static gboolean   gtk_toolbar_button_press         (GtkWidget           *toolbar,
@@ -359,6 +358,16 @@ gtk_toolbar_class_init (GtkToolbarClass *klass)
   widget_class->size_allocate = gtk_toolbar_size_allocate;
   widget_class->style_set = gtk_toolbar_style_set;
   widget_class->focus = gtk_toolbar_focus;
+
+  /* need to override the base class function via override_class_closure,
+   * because the signal slot is not available in GtkWidgetClass
+   */
+  g_signal_override_class_closure (g_signal_lookup ("move_focus",
+                                                    GTK_TYPE_WIDGET),
+                                   GTK_TYPE_TOOLBAR,
+                                   g_cclosure_new (G_CALLBACK (gtk_toolbar_move_focus),
+                                                   NULL, NULL));
+
   widget_class->screen_changed = gtk_toolbar_screen_changed;
   widget_class->realize = gtk_toolbar_realize;
   widget_class->unrealize = gtk_toolbar_unrealize;
@@ -438,25 +447,7 @@ gtk_toolbar_class_init (GtkToolbarClass *klass)
                  G_TYPE_BOOLEAN, 3,
                  G_TYPE_INT, G_TYPE_INT,
                  G_TYPE_INT);
-  /**
-   * GtkToolbar::move-focus:
-   * @toolbar: the #GtkToolbar which emitted the signal
-   * @dir: a #GtkDirection
-   *
-   * A keybinding signal used internally by GTK+. This signal can't
-   * be used in application code.
-   *
-   * Return value: %TRUE if the signal was handled, %FALSE if not
-   */
-  toolbar_signals[MOVE_FOCUS] =
-    _gtk_binding_signal_new (I_("move_focus"),
-                            G_TYPE_FROM_CLASS (klass),
-                            G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                            G_CALLBACK (gtk_toolbar_move_focus),
-                            NULL, NULL,
-                            _gtk_marshal_BOOLEAN__ENUM,
-                            G_TYPE_BOOLEAN, 1,
-                            GTK_TYPE_DIRECTION_TYPE);
+
   /**
    * GtkToolbar::focus-home-or-end:
    * @toolbar: the #GtkToolbar which emitted the signal
@@ -1921,19 +1912,22 @@ gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
 /* Keybinding handler. This function is called when the user presses
  * Ctrl TAB or an arrow key.
  */
-static gboolean
-gtk_toolbar_move_focus (GtkToolbar       *toolbar,
+static void
+gtk_toolbar_move_focus (GtkWidget        *widget,
                        GtkDirectionType  dir)
 {
+  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
+  GtkContainer *container = GTK_CONTAINER (toolbar);
   GList *list;
   gboolean try_focus = FALSE;
   GList *children;
-  GtkContainer *container = GTK_CONTAINER (toolbar);
-  
+
+  g_printerr ("%s (dir = %d)\n", G_STRFUNC, dir);
+
   if (container->focus_child &&
       gtk_widget_child_focus (container->focus_child, dir))
     {
-      return TRUE;
+      return;
     }
   
   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
@@ -1950,8 +1944,6 @@ gtk_toolbar_move_focus (GtkToolbar       *toolbar,
     }
   
   g_list_free (children);
-  
-  return FALSE;
 }
 
 /* The focus handler for the toolbar. It called when the user presses
index 0ac93d79ce2b93a5cc07393eaf176947ed581fc1..59e91f81a4f90c6ddf3370f282e08ea2baba879a 100644 (file)
@@ -77,6 +77,7 @@ enum {
   MNEMONIC_ACTIVATE,
   GRAB_FOCUS,
   FOCUS,
+  MOVE_FOCUS,
   EVENT,
   EVENT_AFTER,
   BUTTON_PRESS_EVENT,
@@ -214,6 +215,8 @@ static gboolean             gtk_widget_real_focus_out_event         (GtkWidget        *widget,
                                                                 GdkEventFocus    *event);
 static gboolean                gtk_widget_real_focus                   (GtkWidget        *widget,
                                                                 GtkDirectionType  direction);
+static void             gtk_widget_real_move_focus              (GtkWidget        *widget,
+                                                                 GtkDirectionType  direction);
 static gboolean                gtk_widget_real_keynav_failed           (GtkWidget        *widget,
                                                                 GtkDirectionType  direction);
 static PangoContext*   gtk_widget_peek_pango_context           (GtkWidget        *widget);
@@ -830,6 +833,16 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                  _gtk_marshal_BOOLEAN__ENUM,
                  G_TYPE_BOOLEAN, 1,
                  GTK_TYPE_DIRECTION_TYPE);
+  widget_signals[MOVE_FOCUS] =
+    _gtk_binding_signal_new (I_("move_focus"),
+                             G_TYPE_FROM_CLASS (object_class),
+                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                             G_CALLBACK (gtk_widget_real_move_focus),
+                             NULL, NULL,
+                             _gtk_marshal_VOID__ENUM,
+                             G_TYPE_NONE,
+                             1,
+                             GTK_TYPE_DIRECTION_TYPE);
   widget_signals[EVENT] =
     g_signal_new (I_("event"),
                  G_TYPE_FROM_CLASS (gobject_class),
@@ -4618,6 +4631,20 @@ gtk_widget_real_focus (GtkWidget         *widget,
     return FALSE;
 }
 
+static void
+gtk_widget_real_move_focus (GtkWidget         *widget,
+                            GtkDirectionType   direction)
+{
+  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+
+  if (GTK_IS_WINDOW (toplevel) &&
+      GTK_WINDOW_GET_CLASS (toplevel)->move_focus)
+    {
+      GTK_WINDOW_GET_CLASS (toplevel)->move_focus (GTK_WINDOW (toplevel),
+                                                   direction);
+    }
+}
+
 static gboolean
 gtk_widget_real_keynav_failed (GtkWidget        *widget,
                                GtkDirectionType  direction)
index b1943d7ec8c56ee6f6dbe22906825f0175d54290..a51c00a7cc76f9e7a671d60ae337b4882f12f1fd 100644 (file)
@@ -57,7 +57,6 @@ enum {
   FRAME_EVENT,
   ACTIVATE_FOCUS,
   ACTIVATE_DEFAULT,
-  MOVE_FOCUS,
   KEYS_CHANGED,
   LAST_SIGNAL
 };
@@ -789,17 +788,6 @@ gtk_window_class_init (GtkWindowClass *klass)
                   G_TYPE_NONE,
                   0);
 
-  window_signals[MOVE_FOCUS] =
-    g_signal_new (I_("move_focus"),
-                  G_TYPE_FROM_CLASS (gobject_class),
-                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                  G_STRUCT_OFFSET (GtkWindowClass, move_focus),
-                  NULL, NULL,
-                  _gtk_marshal_VOID__ENUM,
-                  G_TYPE_NONE,
-                  1,
-                  GTK_TYPE_DIRECTION_TYPE);
-
   window_signals[KEYS_CHANGED] =
     g_signal_new (I_("keys_changed"),
                   G_TYPE_FROM_CLASS (gobject_class),
index c32dc5946ed22ea6af6874c0204038331013c698..2f84c497cb57011f9d46e30105895e79ee7691e2 100644 (file)
@@ -125,6 +125,11 @@ struct _GtkWindowClass
 
   void     (* activate_focus)          (GtkWindow       *window);
   void     (* activate_default)        (GtkWindow       *window);
+
+  /* as of GTK+ 2.12 the "move-focus" signal has been moved to GtkWidget,
+   * so this is merley a virtual function now. Overriding it in subclasses
+   * continues to work though.
+   */
   void     (* move_focus)              (GtkWindow       *window,
                                         GtkDirectionType direction);